package com.joeljhou.project.core;

import com.fazecast.jSerialComm.SerialPort;
import com.joeljhou.project.core.data.DataListener;
import com.joeljhou.project.core.data.DataReceiver;
import com.joeljhou.project.form.Component;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.swing.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 串口助手工具
 */
@Data
@NoArgsConstructor
public class SerialPortManager {

    //模拟接收数据开关(默认false)
    private static Boolean flag = false;

    public static Boolean getFlag() {
        return flag;
    }

    //定义连接的串口
    private static SerialPort port;

    public static SerialPort getConnectionPort() {
        return port;
    }

    /**
     * 获取本地可用的串口详情名称
     */
    public static List<String> getAvailableSerialPorts() {
        return Arrays.stream(SerialPort.getCommPorts())
                .map(x -> {
                    String desc = x.getDescriptivePortName();
                    // 只有Windows下的串口详情名称会包含C
                    int index = desc.indexOf('C');
                    String postDesc = (index >= 0) ? desc.substring(0, index - 1) : desc;
                    return x.getSystemPortName() + "(" + postDesc + ")";
                }).collect(Collectors.toList());
    }

    /**
     * 指定串口连接
     */
    public static Boolean openPort() {
        //根据串口描述文本 获取要打开的串行断开
        SerialPort portInfo = getSerialPortInfo();
        //链接的就是当前端口
        if (port != null && port.getSystemPortName().equals(portInfo.getSystemPortName())) {
            return true;
        }

        // 设置串口参数（波特率、数据位、停止位和奇偶校验）
        portInfo.setComPortParameters(9600, 8, 1, 0);

        // 设置串行端口的读取超时(读取模式、读取超时时间ms、写入超时时间ms)
        /**
         * 常用的读取模式包括：
         * TIMEOUT_READ_BLOCKING：阻塞式读取，直到读取到数据或者超时。
         * TIMEOUT_READ_SEMI_BLOCKING：半阻塞式读取，在读取到数据或者超时之前会循环尝试读取。
         * TIMEOUT_SCANNER：使用Scanner类读取数据。
         */
        portInfo.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 10000, 0);

        boolean isOpen = portInfo.openPort();
        if (isOpen || flag) {
            port = portInfo;
            //定时循环接收数据
            DataReceiver receiver = new DataReceiver();
            DataListener listener = new DataListener();
            receiver.addObserver(listener);
            receiver.receiveData();
        }
        return isOpen;
    }

    /**
     * 断开连接的串口
     */
    public static Boolean closePort() {
        if (port != null && port.isOpen()) {
            boolean isClose = port.closePort();
            if (isClose) {
                port = null;
            }
            return isClose;
        }
        return false;
    }


    //根据串口描述文本获取指定的串口信息
    private static synchronized SerialPort getSerialPortInfo() {
        Component component = Component.getInstance();
        JComboBox portComboBox = component.getPortComboBox();
        int selectedIndex = portComboBox.getSelectedIndex();                     // 获取选择的索引
        String portDescName = (String) portComboBox.getItemAt(selectedIndex);    // 获取选择的文本

        //根据窗口详情名称解析出指定的串口
        int index = portDescName.indexOf('(');
        String portName = portDescName.substring(0, index);
        //获取所有可用串口
        SerialPort[] serialPorts = SerialPort.getCommPorts();
        //获取指定
        List<SerialPort> ports = Arrays.stream(serialPorts).filter(x -> x.getSystemPortName().equals(portName)).collect(Collectors.toList());
        if (ports.size() <= 0) {
            return null;
        }
        return ports.get(0);
    }

}
